home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / all macintosh / wired movies and sprites / watchme / watchme.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  13.7 KB  |  569 lines

  1. //////////
  2. //
  3. //    File:        WatchMe.c
  4. //
  5. //    Contains:    Application-specific code for WatchMe shell.
  6. //
  7. //    Written by:    Tim Monroe
  8. //
  9. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  10. //
  11. //    Change History (most recent first):
  12. //
  13. //       <4>         07/30/98    rtm        added WatchMe_GetLaunchVolumeName
  14. //       <3>         07/28/98    rtm        some clean-up; added WatchMe_EncodeURL
  15. //       <2>         07/25/98    rtm        further enhancements; everything working pretty well now
  16. //       <1>         07/23/98    rtm        first file
  17. //
  18. //    Currently, the movie controller knows how to handle absolute URLs but not relative ones.
  19. //    Here our job is to convert a relative URL into an absolute one. By "relative" we mean that
  20. //    a URL is relative to the location of the movie file.
  21. //       
  22. //////////
  23.  
  24. // header files
  25. #include "WatchMe.h"
  26.   
  27.  
  28. //////////
  29. //
  30. // WatchMe_ConvertRelativeToAbsoluteURL 
  31. // Convert a relative URL to an absolute URL.
  32. //
  33. // On entry, theURLHandle is a handle to a block of memory that contains a URL,
  34. // either absolute or relative. If it's absolute, we don't do anything. If it's
  35. // relative, we convert the URL to an absolute one and return a handle to that
  36. // URL in theURLHandle.
  37. //
  38. // On entry, theRefCon is a handle to a window object record. We use it only to
  39. // obtain the full pathname of the movie file. You could simplify this function
  40. // if you passed the full pathname as a parameter.
  41. //
  42. //////////
  43.  
  44. void WatchMe_ConvertRelativeToAbsoluteURL (Handle theURLHandle, long theRefCon)
  45. {
  46.     WindowObject            myWindowObject = (WindowObject)theRefCon;
  47.     char                    *myMovieFilePath = NULL;
  48.     char                    *myMovieFolderURL = NULL;
  49.     char                    *myGivenURL = NULL;
  50.     char                    myAbsoluteURL[MAX_PATH];
  51.     Size                    mySize = 0;
  52.     int                        myIndex, myCount;
  53.     
  54.     //////////
  55.     //
  56.     // copy the URL passed to this function into a C string
  57.     //
  58.     //////////
  59.     
  60.     mySize = GetHandleSize(theURLHandle);
  61.     if (mySize <= 0)
  62.         goto bail;
  63.     
  64.     myGivenURL = malloc(mySize + 1);
  65.     if (myGivenURL == NULL)
  66.         goto bail;
  67.  
  68.     BlockMove(*theURLHandle, myGivenURL, mySize);
  69.     myGivenURL[mySize] = '\0';
  70.     
  71.     //////////
  72.     //
  73.     // if myGivenURL is already absolute, just return
  74.     //
  75.     //////////
  76.     
  77.     if (WatchMe_IsAbsoluteURL(myGivenURL))
  78.         goto bail;
  79.         
  80.     //////////
  81.     //
  82.     // get the full pathname of the movie file
  83.     //
  84.     //////////
  85.     
  86.     if (myWindowObject == NULL)
  87.         goto bail;
  88.         
  89.     myMovieFilePath = WatchMe_FSSpecToFullPath(&(**myWindowObject).fFileFSSpec);
  90.     if (myMovieFilePath == NULL)
  91.         goto bail;
  92.  
  93.     //////////
  94.     //
  95.     // convert the full pathname of the movie file into a URL to the folder enclosing the movie file
  96.     //
  97.     //////////
  98.     
  99.     myMovieFolderURL = WatchMe_FullPathToURL(myMovieFilePath);
  100.     if (myMovieFolderURL == NULL)
  101.         goto bail;
  102.     
  103.     // strip off the file name, to get the folder name
  104.     myIndex = strlen(myMovieFolderURL) - 1;
  105.     while (myMovieFolderURL[myIndex] != kWM_URLSeparator)
  106.         myIndex--;
  107.     
  108.     myMovieFolderURL[myIndex] = '\0';
  109.     
  110.     //////////
  111.     //
  112.     // if we successfully arrived here, myGivenURL is a URL specified relative to myMovieFolderURL
  113.     //
  114.     // there are three cases to consider:
  115.     // (1) myGivenURL is a file in a folder below the folder myMovieFolderURL
  116.     // (2) myGivenURL is a file in a folder above the folder myMovieFolderURL
  117.     // (3) myGivenURL is a file in the folder myMovieFolderURL
  118.     //
  119.     //////////
  120.     
  121.     myAbsoluteURL[0] = '\0';
  122.     
  123.     if ((myGivenURL[0] == '.') && (myGivenURL[1] == kWM_URLSeparator)) {
  124.     
  125.         //////////
  126.         //
  127.         // (1) myGivenURL is a file in a folder below the folder myMovieFolderURL
  128.         //
  129.         // we assume that myGivenURL begins with the string "./" and that the remainder
  130.         // of myGivenURL is a partial URL path with no further "./" or "../" constructs
  131.         //
  132.         //////////
  133.         
  134.         // take all of the existing myMovieFolderURL 
  135.         strcat(myAbsoluteURL, myMovieFolderURL);
  136.         
  137.         // strip off the initial '.' and append the rest of myGivenURL to myAbsoluteURL
  138.         strcat(myAbsoluteURL, &myGivenURL[1]);
  139.  
  140.     } else if ((myGivenURL[0] == '.') && (myGivenURL[1] == '.') && (myGivenURL[2] == kWM_URLSeparator)) {
  141.     
  142.         //////////
  143.         //
  144.         // (2) myGivenURL is a file in a folder above the folder myMovieFolderURL
  145.         //
  146.         // we assume that myGivenURL begins with one or more consecutive occurrences of
  147.         // the string "../" and that the remainder of myGivenURL is a partial URL path
  148.         // with no further "./" or "../" constructs
  149.         //
  150.         //////////
  151.         
  152.         myIndex = 0;
  153.         while ((myGivenURL[myIndex] == '.') && (myGivenURL[myIndex + 1] == '.') && (myGivenURL[myIndex + 2] == kWM_URLSeparator)) {
  154.  
  155.             // truncate myMovieFolderURL at the rightmost path separator
  156.             myCount = strlen(myMovieFolderURL) - 1;
  157.             while (myMovieFolderURL[myCount] != kWM_URLSeparator)
  158.                 myCount--;
  159.             myMovieFolderURL[myCount] = '\0';
  160.             
  161.             myIndex += 3;
  162.         }
  163.         
  164.         // concatenate the paths for an absolute URL
  165.         strcat(myAbsoluteURL, myMovieFolderURL);
  166.         strcat(myAbsoluteURL, &myGivenURL[myIndex - 1]);
  167.  
  168.     } else {
  169.     
  170.         //////////
  171.         //
  172.         // (3) myGivenURL is a file in the folder myMovieFolderURL
  173.         //
  174.         //////////
  175.     
  176.         // concatenate the paths for an absolute URL
  177.         strcat(myAbsoluteURL, myMovieFolderURL);        
  178.         strcat(myAbsoluteURL, "/");
  179.         strcat(myAbsoluteURL, myGivenURL);
  180.         
  181.     }
  182.     
  183.     //////////
  184.     //
  185.     // return the absolute URL to the caller
  186.     //
  187.     //////////
  188.     
  189.     mySize = (Size)strlen(myAbsoluteURL);
  190.     SetHandleSize(theURLHandle, mySize);
  191.     if (theURLHandle != NULL)
  192.         BlockMove(myAbsoluteURL, *theURLHandle, mySize);
  193.  
  194. bail:
  195.     // dispose of any storage we allocated
  196.     if (myMovieFilePath != NULL)
  197.         free(myMovieFilePath);
  198.     if (myMovieFolderURL != NULL)
  199.         free(myMovieFolderURL);
  200.     if (myGivenURL != NULL)
  201.         free(myGivenURL);
  202. }
  203.  
  204.  
  205. //////////
  206. //
  207. // WatchMe_GetLaunchVolumeName 
  208. // Return the name of the volume from which this application was launched,
  209. // in a form that can be embedded in a full pathname.
  210. // 
  211. // On Macintosh, this is just the volume's name; on Windows, this is the
  212. // drive letter and colon (and NOT the volume's name).
  213. //
  214. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  215. //
  216. //////////
  217.  
  218. char *WatchMe_GetLaunchVolumeName (void)
  219. {
  220.     char                    *myVolName = NULL;
  221. #if TARGET_OS_MAC
  222.     ProcessSerialNumber        myPSN;
  223.     OSErr                    myErr = noErr;
  224. #endif
  225.  
  226.     myVolName = malloc(MAX_PATH);
  227.     if (myVolName == NULL)
  228.         goto bail;
  229.         
  230.     myVolName[0] = '\0';
  231.  
  232.     //////////
  233.     //
  234.     // on Windows, we can use GetCurrentDirectory to get the name of the current directory
  235.     //
  236.     //////////
  237. #if TARGET_OS_WIN32
  238.     
  239.     GetCurrentDirectory(MAX_PATH, myVolName);
  240.         
  241. #if TESTING_ON_NONCD
  242.     myVolName[0] = 'E';        // just testing on my local machine, which uses "E" for the CD-ROM
  243. #else
  244.     myVolName[0] = toupper(myVolName[0]);
  245. #endif
  246.     
  247.     // add the ":" that terminates drive names
  248.     myVolName[1] = ':';
  249.     myVolName[2] = '\0';
  250.  
  251. #endif // TARGET_OS_WIN32
  252.  
  253.     //////////
  254.     //
  255.     // on Macintosh, we'll use the Process Manager
  256.     //
  257.     //////////
  258. #if TARGET_OS_MAC
  259.     myErr = GetCurrentProcess(&myPSN);
  260.     if (myErr == noErr) {
  261.         ProcessInfoRec        myInfo;
  262.         FSSpec                myFSSpec;
  263.         int                    myPos = 0;
  264.     
  265.         myInfo.processInfoLength = sizeof(ProcessInfoRec);
  266.         myInfo.processName = NULL;
  267.         myInfo.processAppSpec = &myFSSpec;
  268.     
  269.         myErr = GetProcessInformation(&myPSN, &myInfo);
  270.         if (myErr == noErr) {
  271.             // get the full pathname of the application file
  272.             myVolName = WatchMe_FSSpecToFullPath(myInfo.processAppSpec);
  273.             
  274.             // truncate before the first path separator
  275.             myPos = strcspn(myVolName, ":");
  276.             myVolName[myPos] = '\0';
  277.         }
  278.     }
  279.     
  280. #if TESTING_ON_NONCD
  281.     myVolName[0] = '\0';
  282.     strcat(myVolName, "QT3SDK");
  283. #endif
  284.  
  285. #endif // TARGET_OS_MAC
  286.  
  287. bail:
  288.     return(myVolName);
  289. }
  290.  
  291.  
  292. //////////
  293. //
  294. // WatchMe_FSSpecToFullPath 
  295. // Convert an FSSpec into a full native path name.
  296. //
  297. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  298. //
  299. //////////
  300.  
  301. static char *WatchMe_FSSpecToFullPath (const FSSpec *theFSSpec)
  302. {
  303.     char        *myPathName = NULL;
  304. #if TARGET_OS_MAC    
  305.     Handle        myHandle = NULL;
  306.     short        myLength;
  307. #endif
  308.  
  309.     if (theFSSpec == NULL)
  310.         goto bail;
  311.  
  312.     myPathName = malloc(MAX_PATH);
  313.     if (myPathName == NULL)
  314.         goto bail;
  315.  
  316. #if TARGET_OS_WIN32
  317.     // on Windows, this is easy (thanks to those hardworking QuickTime engineers)
  318.     FSSpecToNativePathName(theFSSpec, myPathName, MAX_PATH, kFullNativePath);    
  319. #elif TARGET_OS_MAC    
  320.     // on Macintosh, this is easy (thanks to that hardworking Jim Luther)
  321.     WatchMe_FSpGetFullPath(theFSSpec, &myLength, &myHandle);
  322.     BlockMove(*myHandle, myPathName, myLength);
  323.     myPathName[myLength] = '\0';
  324. #endif
  325.  
  326. bail:
  327.     return(myPathName);
  328. }
  329.  
  330.  
  331. //////////
  332. //
  333. // WatchMe_FullPathToURL 
  334. // Convert a full native pathname into an absolute local URL.
  335. //
  336. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  337. //
  338. //////////
  339.  
  340. static char *WatchMe_FullPathToURL (char *thePath)
  341. {
  342.     char        *myURL = NULL;    
  343.     int            myIndex;
  344.  
  345.     if (thePath == NULL)
  346.         goto bail;
  347.  
  348.     myURL = malloc(MAX_PATH);
  349.     if (myURL == NULL)
  350.         goto bail;
  351.  
  352.     //////////
  353.     //
  354.     // convert all native path separators into the URL path separator
  355.     //
  356.     //////////
  357.     
  358.     for (myIndex = 0; myIndex < strlen(thePath); myIndex++)
  359.         if (thePath[myIndex] == kWM_PathSeparator)
  360.             thePath[myIndex] = kWM_URLSeparator;
  361.  
  362.     //////////
  363.     //
  364.     // convert any special characters in the URL path into their encoded versions;
  365.     // in theory, the URLs we are passed should already be encoded, but we'll make
  366.     // sure before passing the URL to the movie controller
  367.     //
  368.     //////////
  369.     
  370.     thePath = WatchMe_EncodeURL(thePath);
  371.     
  372.     //////////
  373.     //
  374.     // prepend the appropriate URL head
  375.     //
  376.     //////////
  377.  
  378.     myURL[0] = '\0';
  379.     strcat(myURL, "file:///");
  380.  
  381.     //////////
  382.     //
  383.     // append the converted path name to the URL
  384.     //
  385.     //////////
  386.  
  387.     strcat(myURL, thePath);
  388.     
  389. bail:
  390.     return(myURL);
  391. }
  392.  
  393.  
  394. //////////
  395. //
  396. // WatchMe_EncodeURL 
  397. // Convert any special characters in the specified URL path into their encoded versions.
  398. //
  399. // Currently, only the space character ' ' is treated specially.
  400. //
  401. // Note that this encoding might cause the size of the string to increase; in that case,
  402. // we'll allocate some new storage and free theURL before returning.
  403. //
  404. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  405. //
  406. //////////
  407.  
  408. static char *WatchMe_EncodeURL (char *theURL)
  409. {
  410.     char        *myEncodedURL = NULL;    
  411.     char        *mySpecialChar = NULL;    
  412.     int            myPos, myIndex;
  413.  
  414.     if (theURL == NULL)
  415.         goto bail;
  416.  
  417.     // determine whether we actually need to do any work
  418.     mySpecialChar = strchr(theURL, ' ');
  419.     if (mySpecialChar == NULL) {
  420.         myEncodedURL = theURL;            // return the string we were passed
  421.         goto bail;
  422.     }
  423.     
  424.     // theURL contains one or more special characters that need to be encoded;
  425.     // allocate a new string into which we can write the encoded URL
  426.     myEncodedURL = malloc(MAX_PATH);
  427.     if (myEncodedURL == NULL)
  428.         goto bail;
  429.  
  430.     myPos = 0;
  431.     for (myIndex = 0; myIndex < strlen(theURL); myIndex++) {
  432.         if (theURL[myIndex] == ' ') {
  433.             char    myChar;
  434.             
  435.             myEncodedURL[myPos + 0] = '%';            
  436.             myChar = theURL[myIndex] >> 4;
  437.             myEncodedURL[myPos + 1] = myChar + ((myChar <= 9) ? '0' : ('A' - 10));
  438.             myChar = theURL[myIndex] & 0xF;
  439.             myEncodedURL[myPos + 2] = myChar + ((myChar <= 9) ? '0' : ('A' - 10));
  440.             myPos += 3;        
  441.         } else {
  442.             myEncodedURL[myPos] = theURL[myIndex];
  443.             myPos++;        
  444.         }
  445.     }
  446.     
  447.     myEncodedURL[myPos] = '\0';
  448.     free(theURL);
  449.     
  450. bail:
  451.     return(myEncodedURL);
  452. }
  453.  
  454.  
  455. //////////
  456. //
  457. // WatchMe_IsAbsoluteURL 
  458. // Determine whether the specified URL is absolute.
  459. //
  460. //////////
  461.  
  462. static Boolean WatchMe_IsAbsoluteURL (char *theURL)
  463. {
  464.     return(theURL[0] != '.');
  465. }
  466.  
  467.  
  468. //////////
  469. //
  470. // WatchMe_FSpGetFullPath 
  471. // Get a full path name from an FSSpec.
  472. //
  473. // This is straight out of MoreFiles 1.4 by Jim Luther; the only thing I did
  474. // was to change the name.
  475. //
  476. // NOTE: This function is MACINTOSH ONLY.
  477. //
  478. //////////
  479.  
  480. static OSErr WatchMe_FSpGetFullPath (const FSSpec *spec, short *fullPathLength, Handle *fullPath)
  481. {
  482.     OSErr        result;
  483.     FSSpec        tempSpec;
  484.     CInfoPBRec    pb;
  485.     
  486.     *fullPathLength = 0;
  487.     *fullPath = NULL;
  488.     
  489.     /* Make a copy of the input FSSpec that can be modified */
  490.     BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
  491.     
  492.     if ( tempSpec.parID == fsRtParID )
  493.     {
  494.         /* The object is a volume */
  495.         
  496.         /* Add a colon to make it a full pathname */
  497.         ++tempSpec.name[0];
  498.         tempSpec.name[tempSpec.name[0]] = ':';
  499.         
  500.         /* We're done */
  501.         result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  502.     }
  503.     else
  504.     {
  505.         /* The object isn't a volume */
  506.         
  507.         /* Is the object a file or a directory? */
  508.         pb.dirInfo.ioNamePtr = tempSpec.name;
  509.         pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  510.         pb.dirInfo.ioDrDirID = tempSpec.parID;
  511.         pb.dirInfo.ioFDirIndex = 0;
  512.         result = PBGetCatInfoSync(&pb);
  513.         if ( result == noErr )
  514.         {
  515.             /* if the object is a directory, append a colon so full pathname ends with colon */
  516.             if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  517.             {
  518.                 ++tempSpec.name[0];
  519.                 tempSpec.name[tempSpec.name[0]] = ':';
  520.             }
  521.             
  522.             /* Put the object name in first */
  523.             result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  524.             if ( result == noErr )
  525.             {
  526.                 /* Get the ancestor directory names */
  527.                 pb.dirInfo.ioNamePtr = tempSpec.name;
  528.                 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  529.                 pb.dirInfo.ioDrParID = tempSpec.parID;
  530.                 do    /* loop until we have an error or find the root directory */
  531.                 {
  532.                     pb.dirInfo.ioFDirIndex = -1;
  533.                     pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  534.                     result = PBGetCatInfoSync(&pb);
  535.                     if ( result == noErr )
  536.                     {
  537.                         /* Append colon to directory name */
  538.                         ++tempSpec.name[0];
  539.                         tempSpec.name[tempSpec.name[0]] = ':';
  540.                         
  541.                         /* Add directory name to beginning of fullPath */
  542.                         (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
  543.                         result = MemError();
  544.                     }
  545.                 } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
  546.             }
  547.         }
  548.     }
  549.     if ( result == noErr )
  550.     {
  551.         /* Return the length */
  552.         *fullPathLength = InlineGetHandleSize(*fullPath);
  553.     }
  554.     else
  555.     {
  556.         /* Dispose of the handle and return NULL and zero length */
  557.         if ( *fullPath != NULL )
  558.         {
  559.             DisposeHandle(*fullPath);
  560.         }
  561.         *fullPath = NULL;
  562.         *fullPathLength = 0;
  563.     }
  564.     
  565.     return ( result );
  566. }
  567.  
  568.  
  569.